package com.universest.swordholder.data
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import android.content.Context
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.universest.swordholder.data.dao.Book
import com.universest.swordholder.data.dao.BookDao
import com.universest.swordholder.data.dao.LongText
import com.universest.swordholder.data.dao.LongTextDao
import com.universest.swordholder.data.dao.Passage
import com.universest.swordholder.data.dao.PassageDao
import com.universest.swordholder.data.dao.Volume
import com.universest.swordholder.data.dao.VolumeDao
import com.universest.swordholder.getApplicationContext
import com.universest.swordholder.model.user.UserManager

/**
 * 数据库版本号，用于数据库升级控制。
 */
const val userDatabaseVersion = 5;

/**
 * 用户数据库抽象类，使用Room持久化库实现SQLite数据库访问。
 * 包含四个实体：书籍(Book)、长文本(LongText)、卷(Volume)、段落(Passage)。
 * 提供对应的DAO接口以进行数据操作。
 *
 * @property version 当前数据库版本号
 * @property entities 数据库中包含的实体类列表
 * @property exportSchema 是否导出数据库模式文件（此处设为false）
 */
@Database(entities = [Book::class, LongText::class, Volume::class, Passage::class], version = userDatabaseVersion, exportSchema = false)
abstract class UserDatabase : RoomDatabase() {

    /**
     * 获取书籍数据访问对象(BookDao)，用于执行与书籍相关的数据库操作。
     *
     * @return BookDao 实例
     */
    abstract fun bookDao(): BookDao

    /**
     * 获取长文本数据访问对象(LongTextDao)，用于执行与长文本相关的数据库操作。
     *
     * @return LongTextDao 实例
     */
    abstract fun longTextDao(): LongTextDao

    /**
     * 获取卷数据访问对象(VolumeDao)，用于执行与卷相关的数据库操作。
     *
     * @return VolumeDao 实例
     */
    abstract fun volumeDao(): VolumeDao

    /**
     * 获取段落数据访问对象(PassageDao)，用于执行与段落相关的数据库操作。
     *
     * @return PassageDao 实例
     */
    abstract fun passageDao(): PassageDao

    companion object {
        /**
         * 存储不同用户ID对应数据库实例的映射表，保证每个用户拥有独立的数据库连接。
         * 使用volatile关键字确保多线程环境下的可见性。
         */
        @Volatile
        private var INSTANCES: MutableMap<String, UserDatabase> = mutableMapOf()
        private val lock = Any()

        /**
         * 数据库从版本1到版本2的迁移策略。
         * 在book表中新增lastBrowsePassageId字段，默认值为-1。
         */
        private val MIGRATION_1_2 = object : Migration(1, 2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.execSQL("ALTER TABLE book ADD COLUMN lastBrowsePassageId INTEGER NOT NULL DEFAULT -1")
            }
        }

        private val MIGRATION_2_3 = object : Migration(2, 3) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.execSQL("ALTER TABLE volume ADD COLUMN extInfo TEXT NOT NULL DEFAULT ''")
            }
        }

        private val MIGRATION_3_4 = object : Migration(3, 4) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.execSQL("ALTER TABLE passage ADD COLUMN charCount INTEGER NOT NULL DEFAULT 0")
            }
        }

        private val MIGRATION_4_5 = object : Migration(4, 5) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.execSQL("ALTER TABLE volume ADD COLUMN summaryId INTEGER NOT NULL DEFAULT -1")
                database.execSQL("ALTER TABLE volume ADD COLUMN summaryUse INTEGER NOT NULL DEFAULT 0")
            }
        }

        /**
         * 根据指定上下文和用户ID获取该用户的数据库实例。
         * 若已存在则直接返回缓存中的实例；否则创建新的数据库实例并加入缓存。
         *
         * @param context 应用程序上下文，用于构建数据库
         * @param userId 用户唯一标识符，用于区分不同的数据库文件
         * @return 对应用户的UserDatabase实例
         */
        fun getInstance(context: Context, userId: String): UserDatabase {
            return INSTANCES[userId] ?: synchronized(lock) {
                INSTANCES.getOrPut(userId) {
                    Room.databaseBuilder(
                        context.applicationContext,
                        UserDatabase::class.java,
                        "sh_${userId}.db"
                    )
                        .addMigrations(MIGRATION_1_2,MIGRATION_2_3,MIGRATION_3_4,MIGRATION_4_5)
                        .build()
                }
            }
        }
    }
}

/**
 * 获取当前登录用户的数据库实例。
 * 通过UserManager获取当前用户ID，并调用UserDatabase.getInstance方法获得数据库实例。
 *
 * @return 当前用户的UserDatabase实例
 */
fun getUserDb() : UserDatabase{
    return UserDatabase.getInstance(getApplicationContext(), UserManager.instance.currentUserId.toString())
}
